package oakclub.service;

import com.restfb.DefaultFacebookClient;
import com.restfb.FacebookClient;
import com.restfb.json.JsonArray;
import com.restfb.json.JsonObject;
import oakclub.entity.*;
import oakclub.global.Config;
import oakclub.global.Container;
import oakclub.global.Context;
import oakclub.global.DateFormatter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class FacebookService
{
    private final String appId = Config.get("facebook.app.id");
    private final String appSecret = Config.get("facebook.app.secret");
    private final Logger logger = LoggerFactory.getLogger(FacebookService.class);

    private final String DEFAULT_AVATAR_URL = "http://graph.facebook.com/%d/picture";
    private final LocationEntity DEFAULT_LOCATION = new LocationEntity(1.0, 1.0);

    public String getToken()
    {
        return Context.get().getFbToken();
    }

    private int convert2GenderId(String fbGender)
    {
        switch(fbGender.toLowerCase())
        {
            case "male":
                return GenderEntity.Gender.MALE.getId();
            case "female":
                return GenderEntity.Gender.FEMALE.getId();
            default:
                return GenderEntity.Gender.UNKNOWN.getId();
        }
    }

    private int convert2RelationshipId(String fbRelationship)
    {
        switch(fbRelationship.toLowerCase())
        {
            case "single":
                return RelationshipEntity.Relationship.SINGLE.getId();
            case "in a relationship":
                return RelationshipEntity.Relationship.IN_A_RELATIONSHIP.getId();
            case "in a engaged":
                return RelationshipEntity.Relationship.ENGAGED.getId();
            case "married":
                return RelationshipEntity.Relationship.MARRIED.getId();
            case "it's complicated":
                return RelationshipEntity.Relationship.COMPLICATED.getId();
            case "in an open relationship":
                return RelationshipEntity.Relationship.IN_AN_OPEN_RELATIONSHIP.getId();
            case "widowed":
                return RelationshipEntity.Relationship.WIDOWED.getId();
            case "separated":
                return RelationshipEntity.Relationship.SEPARATED.getId();
            case "divorced":
                return RelationshipEntity.Relationship.DIVORCED.getId();
            default:
                return RelationshipEntity.Relationship.UNKNOWN.getId();
        }
    }

    public String getAvatarUrl(long userId)
    {
        return String.format(this.DEFAULT_AVATAR_URL, userId);
    }

    public long getUserId() throws Exception
    {
        String query = "SELECT uid FROM user WHERE uid = me()";
        FacebookClient facebookClient = new DefaultFacebookClient(this.getToken(), this.appSecret);
        JsonObject jsonResponse = facebookClient.executeFqlQuery(query, JsonObject.class).get(0);
        long userId = jsonResponse.getLong("uid");

        return userId;
    }

    public UserEntity getUser(long userId) throws Exception
    {
        // query from fb
        String query = "SELECT name, first_name, last_name, username, email, sex, relationship_status, birthday_date, current_location.latitude, current_location.longitude, hometown_location.latitude, hometown_location.longitude, work.employer, education.school FROM user WHERE uid = " + userId;
        FacebookClient facebookClient = new DefaultFacebookClient(this.getToken(), this.appSecret);
        JsonObject jsonResponse = facebookClient.executeFqlQuery(query, JsonObject.class).get(0);

        // location
        LocationEntity location = null;
        try
        {
            JsonObject jsonLocation = jsonResponse.getJsonObject("current_location");
            location = new LocationEntity(jsonLocation.getDouble("latitude"), jsonLocation.getDouble("longitude"));
        }
        catch(Exception e)
        {
            GeoService geoService = (GeoService) Container.getComponent(GeoService.class);
            location = geoService.getLocation();
            if(location == null)
            {
                location = this.DEFAULT_LOCATION;
            }
        }

        // hometown
        LocationEntity hometown = null;
        try
        {
            JsonObject jsonLocation = jsonResponse.getJsonObject("hometown_location");
            hometown = new LocationEntity(jsonLocation.getDouble("latitude"), jsonLocation.getDouble("longitude"));
        }
        catch(Exception e) { }

        // schools
        List<SchoolEntity> schools = new ArrayList<>();
        JsonArray jsonSchools = jsonResponse.getJsonArray("education");
        if(jsonSchools != null)
        {
            int numSchool = jsonSchools.length();
            for(int i = 0; i < numSchool; i++)
            {
                JsonObject jsonSchool = jsonSchools.getJsonObject(i).getJsonObject("school");
                schools.add(new SchoolEntity(jsonSchool.getLong("id"), jsonSchool.getString("name")));
            }
        }

        // works
        List<WorkEntity> works = new ArrayList<>();
        JsonArray jsonWorks = jsonResponse.getJsonArray("work");
        int numWorks = jsonWorks.length();
        for(int i = 0; i < numWorks; i++)
        {
            JsonObject jsonWork = jsonWorks.getJsonObject(i).getJsonObject("employer");
            works.add(new WorkEntity(jsonWork.getLong("id"), jsonWork.getString("name")));
        }

        // convert data
        int genderId = this.convert2GenderId(jsonResponse.getString("sex"));
        int relationshipId = this.convert2RelationshipId(jsonResponse.getString("relationship_status"));
        Date birthday = DateFormatter.getFormatter("MM/dd/yyyy").parse(jsonResponse.getString("birthday_date"));

        // parse user
        UserEntity user = new UserEntity();
        user.setId(userId);
        user.setName(jsonResponse.getString("name"));
        user.setFirstName(jsonResponse.getString("first_name"));
        user.setLastName(jsonResponse.getString("last_name"));
        user.setUsername(jsonResponse.getString("username"));
        user.setEmail(jsonResponse.getString("email"));
        user.setGender(new GenderEntity(genderId));
        user.setRelationship(new RelationshipEntity(relationshipId));
        user.setBirthday(birthday);
        user.setLocation(location);
        user.setHometown(hometown);
        user.setSchools(schools);
        user.setWorks(works);

        return user;
    }

    public List<FriendEntity> getFriendlist(long userId) throws Exception
    {
        // query from fb
        String query = String.format("SELECT uid, name, sex FROM user WHERE uid IN (SELECT uid2 FROM friend WHERE uid1 = %d)", userId);
        FacebookClient facebookClient = new DefaultFacebookClient(this.getToken(), this.appSecret);
        List<JsonObject> jsonResponse = facebookClient.executeFqlQuery(query, JsonObject.class);

        // parse
        List<FriendEntity> friends = new ArrayList<>();
        for(JsonObject jsonFriend : jsonResponse)
        {
            long friendId = jsonFriend.getLong("uid");
            String name = jsonFriend.getString("name");
            int genderId = this.convert2GenderId(jsonFriend.getString("sex"));
            friends.add(new FriendEntity(friendId, name, genderId));
        }

        return friends;
    }

    public List<JsonObject> getPhotos(long userId)
    {
        String query = String.format("SELECT src_big,modified FROM photo WHERE aid IN (SELECT aid FROM album WHERE owner = %s AND type = 'profile') LIMIT 10", userId);
        FacebookClient facebookClient = new DefaultFacebookClient(this.getToken(), this.appSecret);
        return facebookClient.executeFqlQuery(query, JsonObject.class);
    }
}
